package com.beta.mq.redis.aop;

import com.alibaba.fastjson.JSON;
import com.beta.cat.utils.GJsonUtil;
import com.beta.cat.utils.GuidUtil;
import com.beta.elephant.vo.ResultVO;
import com.beta.mq.redis.constant.CommonConstant;
import com.beta.mq.redis.constant.TopicConstant;
import com.beta.mq.redis.constant.TransCode;
import com.beta.mq.redis.model.FlowData;
import com.beta.mq.redis.model.Message;
import com.beta.mq.redis.producer.Producer;
import com.beta.mq.redis.producer.annotation.TransFlow;
import com.beta.mq.redis.user.CurrentUserInvoker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @Author yliu2
 * @Date 2023/8/10 15:09
 * @Description 交易流水采集
 */

@Slf4j
@Aspect
@Order(1)
public class TransFlowAspect {

    private static final Integer ERROR_CODE = 1105;

    private static final String POD_PROPERTY = "webgate.agent.name";

    @Autowired
    private Producer producer;

    @Autowired
    private CurrentUserInvoker currentUserInvoker;

    @Around("@annotation(com.beta.mq.redis.producer.annotation.TransFlow)")
    public Object aroundMethod(ProceedingJoinPoint point) throws Throwable {
        // 获取目标方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Object result;

        TransFlow transFlow = method.getAnnotation(TransFlow.class);
        LocalDateTime startTime = LocalDateTime.now();
        Integer code = ResultVO.success().getCode();//默认为成功

        try {
            result = point.proceed(point.getArgs());
            if (result instanceof ResultVO) {
                ResultVO resultVo = (ResultVO) result;
                code = resultVo.getCode();
            }
        } catch (Throwable e) {
            code = ERROR_CODE;
            throw e;
        } finally {
            //获取入参转换成对应的交易流水编码
            //记录交易流水
            takeTransFlow(transFlow, startTime, code);
        }
        return result;
    }


    private void takeTransFlow(TransFlow transFlow, LocalDateTime start, Integer resultCode) {
        FlowData collect = new FlowData();
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
            String currentUserId = currentUserInvoker.getCurrentUserId(request, response);
            if (StringUtils.isEmpty(currentUserId)) {
                return;
            }
            collect.setTransOrigin(currentUserId);
            collect.setSerialNo(GuidUtil.getGuid());
            collect.setTransDate(start.toLocalDate());
            collect.setStartTime(start);
            collect.setEndTime(LocalDateTime.now());
            collect.setResultCode(resultCode);
            collect.setPodName(System.getProperty(POD_PROPERTY));
            dealCodeAndType(transFlow, collect);
            if (resultCode != null && ResultVO.success().getCode().intValue() == resultCode.intValue()
                    && collect.getEndTime().minusSeconds(1).isBefore(collect.getStartTime())) {//正常输出，则info级别
                log.info("trans flow record msg:{}" + JSON.toJSONString(collect));
            } else {
                log.warn("trans flow record msg:{}" + JSON.toJSONString(collect));
            }
            setCustId(collect);
            producer.sendMessage(TopicConstant.TRANS_FLOW, new Message(collect));
        } catch (Throwable e) {
            log.error("交易流水：{}记录异常", transFlow.transCode(), e);
        }
    }

    /*
     * 理财经理主页 理财经理预览页 获取客户，保存到财富阶梯访问流水表
     */
    private void setCustId(FlowData collect) {
        //财富阶梯是GET请求，在请求参数里获取，其余业务根据不同情况调整
        if (TransCode.CUST_WEALTH_LADDER.equals(collect.getTransCode()) || TransCode.CUST_WEALTH_PREVIEW_LADDER.equals(collect.getTransCode())) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            collect.setCustId(request.getParameter("custId"));
            log.info("理财经理访问页面明细:{}", GJsonUtil.toJson(collect));
        }
    }


    private void dealCodeAndType(TransFlow transFlow, FlowData collect) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String transCode = transFlow.transCode();
        String[] params = transFlow.buryingPointParams();
        //交易编码转换  同一接口映射多个码值  匹配对应的page

        int length = ArrayUtils.isNotEmpty(params) ? params.length : 0;
        if (length == 1) {
            transCode = transCode + request.getParameter(params[0]);
        }

        //内容tab页需要两个参数区分。
        if (length == 2) {
            if (StringUtils.isNotEmpty(request.getParameter(params[0]))) {
                //主页的任何请求都统计了。若主页内的公募产品搜索无需统计 进一步判断params[1]
                transCode = transCode + "0";
            } else {
                transCode = transCode + request.getParameter(params[1]);
            }
        }
        collect.setTransCode(transCode);

        //通过shardId判断 是否为分享

        // 1-理财师  2-客户
        int userType = getUserType(request, transCode);
        collect.setUserType(userType);
    }


    /**
     * @param request
     * @param transCode
     * @return 1-理财师  2-客户
     */
    private Integer getUserType(HttpServletRequest request, String transCode) {
        if (TransCode.WX_AUTH_TOKEN.equals(transCode)) {
            String state = request.getParameter("state");
            if(StringUtils.isEmpty(state)){
               return null;
            }
            String[] splits = state.split("_");
            String authChannel = splits[0];
            //selfApp  自建应用授权
            return "selfApp".equals(authChannel) ? 1 : 2;
        }
        //其他接口通过请求头的shareId区分
        String shareId = request.getHeader(CommonConstant.SHARE);
        return StringUtils.isEmpty(shareId) ? 1 : 2;
    }


}
